#include "QQSystemApi.h"

QString QQSystemApi::getDeviceUuid()
{
	QString result;
#ifdef Q_OS_WIN
	GUID guid;
	if (CoCreateGuid(&guid) == S_OK) {
		result = QString("%1-%2-%3-%4%5-%6%7%8%9%10%11%12")
			.arg(guid.Data1, 8, 16, QChar('0'))
			.arg(guid.Data2, 4, 16, QChar('0'))
			.arg(guid.Data3, 4, 16, QChar('0'))
			.arg(guid.Data4[0], 2, 16, QChar('0'))
			.arg(guid.Data4[1], 2, 16, QChar('0'))
			.arg(guid.Data4[2], 2, 16, QChar('0'))
			.arg(guid.Data4[3], 2, 16, QChar('0'))
			.arg(guid.Data4[4], 2, 16, QChar('0'))
			.arg(guid.Data4[5], 2, 16, QChar('0'))
			.arg(guid.Data4[6], 2, 16, QChar('0'))
			.arg(guid.Data4[7], 2, 16, QChar('0'))
			.toUpper();
	}
	else {
		qCritical() << "can not get device uuid : device windows";
		return QString();
	}
#elif Q_OS_UNIX
	uuid_t u;
	uuid_generate(u);
	result.reserve(36);
	for (int i = 0; i < 16; i++) {
		result.append(QString::number(u[i], 16).rightJustified(2, '0'));
		if (i == 3 || i == 5 || i == 7 || i == 9) {
			result.append('-');
		}
	}
	result = result.toUpper();
#endif
	return result;
}

bool QQSystemApi::checkUniqueProcessAccount(const QString& account)
{
	QSharedMemory sharedMemory("unique_key_for_shared_memory_" + account);
	if (!sharedMemory.isAttached()) {
		if (!sharedMemory.attach()) {
			qCritical() << sharedMemory.key() + " " + sharedMemory.errorString();
			return false;
		}
	}

	if (sharedMemory.size() == 0) {
		sharedMemory.create(1024);
		qWarning() << sharedMemory.key() + " " + sharedMemory.errorString();
		sharedMemory.lock();
		bool* flag = static_cast<bool*>(sharedMemory.data());
		*flag = false;
		sharedMemory.unlock();
		if (!sharedMemory.attach()) {
			qCritical() << sharedMemory.key() + " " + sharedMemory.errorString();
			return false;
		}
	}

	sharedMemory.lock();
	bool* flag = static_cast<bool*>(sharedMemory.data());
	bool result = *flag;
	if (!*flag) *flag = true;
	sharedMemory.unlock();
	return !result;
}

void QQSystemApi::exitClearSharedMemory(const QString& account)
{
	QSharedMemory sharedMemory("unique_key_for_shared_memory_" + account);
	if (sharedMemory.isAttached()) {
		sharedMemory.lock();
		bool* flag = static_cast<bool*>(sharedMemory.data());
		*flag = false;
		sharedMemory.unlock();
		if (!sharedMemory.detach()) {
			qCritical() << sharedMemory.key() + " " + sharedMemory.errorString();
		}
	}
}

QImage QQSystemApi::applyEffectToImage(QImage image, QGraphicsEffect* effect, int extent)
{
	if (image.isNull()) return QImage();
	if (!effect) return image;

	QGraphicsScene scene;
	QGraphicsPixmapItem item;
	item.setPixmap(QPixmap::fromImage(image));
	item.setGraphicsEffect(effect);
	scene.addItem(&item);

	QImage result(image.size() + QSize(extent * 2, extent * 2), QImage::Format_ARGB32);
	result.fill(Qt::transparent);
	QPainter painter(&result);
	scene.render(&painter, QRectF(), QRectF(-extent, -extent, image.width() + extent * 2, image.height() + extent * 2));
	return result;
}

QPixmap QQSystemApi::applyEffectToPixmap(QPixmap pixmap, QGraphicsEffect* effect, int extent)
{
	QGraphicsScene scene;
	QGraphicsPixmapItem item;
	item.setPixmap(pixmap);
	item.setGraphicsEffect(effect);
	scene.addItem(&item);

	QPixmap result(pixmap.size() + QSize(extent * 2, extent * 2));
	result.fill(Qt::transparent);
	QPainter painter(&result);
	scene.render(&painter, QRectF(), QRectF(-extent, -extent, pixmap.width() + extent * 2, pixmap.height() + extent * 2));
	return result;
}

QPixmap QQSystemApi::applyEffectToPixmap(QPixmap pixmap, int radius, int extent, QColor defaultColor)
{
	QGraphicsScene scene;
	QGraphicsPixmapItem item;
	item.setPixmap(pixmap);

	QGraphicsBlurEffect effect;
	effect.setBlurRadius(radius);
	item.setGraphicsEffect(&effect);
	scene.addItem(&item);

	QPixmap result(pixmap.size() + QSize(extent * 2, extent * 2));
	result.fill(defaultColor);
	QPainter painter(&result);
	scene.render(&painter, QRectF(), QRectF(-extent, -extent, pixmap.width() + extent * 2, pixmap.height() + extent * 2));
	return result;
}

QMimeType QQSystemApi::getFileMimeType(const QString& filename)
{
	static QMimeDatabase db;
	return db.mimeTypeForFile(filename, QMimeDatabase::MatchContent);
}

bool QQSystemApi::mouseInWidget(QWidget* widget)
{
	QPoint pos = QCursor::pos();
	QPoint widgetPos = widget->mapToGlobal(QPoint(0, 0));
	QRect widgetRect = widget->rect();
	QRect rect(widgetPos, widgetRect.size());
	return rect.contains(pos);
}

bool QQSystemApi::posInWidget(QWidget* widget, QPoint point)
{
	QPoint widgetPos = widget->mapToGlobal(QPoint(0, 0));
	QRect widgetRect = widget->rect();
	QRect rect(widgetPos, widgetRect.size());
	return rect.contains(point);
}

QString QQSystemApi::generateAbsoluteUuidByStringList(const QStringList& list)
{
	QStringList real = list;
	real.sort();
	QString merge = real.join(" ");
	QByteArray byte = merge.toUtf8();
	QByteArray data = QCryptographicHash::hash(byte, QCryptographicHash::Md5);
	return QString(data.toHex());
}

QString QQSystemApi::generateFileUniqueKey(const QString& filename)
{
	return QString();
}

int QQSystemApi::getCpuCoreCount()
{
	return QThread::idealThreadCount();
}

QImage QQSystemApi::generateQrCode(const QString& url, int size)
{
	int margin = 20;
	QImage qrCodeImage(size, size, QImage::Format_RGB32);
	qrCodeImage.fill(Qt::white);
	qrcodegen::QrCode qrCode = qrcodegen::QrCode::encodeText(url.toUtf8(), qrcodegen::QrCode::Ecc::LOW);

	int px = (size - 2 * margin) / qrCode.getSize();
	QPainter painter(&qrCodeImage);
	painter.setRenderHint(QPainter::Antialiasing);
	QColor fgColor(0, 0, 0);
	QColor bgColor(255, 255, 255);
	for (int i = 0; i < qrCode.getSize(); i++)
	{
		for (int j = 0; j < qrCode.getSize(); j++)
		{
			if (qrCode.getModule(j, i))
			{
				painter.fillRect(margin + j * px, margin + i * px, px, px, fgColor);
			}
			else {
				painter.fillRect(margin + j * px, margin + i * px, px, px, bgColor);
			}
		}
	}
	return qrCodeImage;
}

QString QQSystemApi::generateRandomText(int min, int max)
{
	const QString possibleCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
	const int possibleCharactersLength = possibleCharacters.length();
	int realLength = min + rand() % (max - min) + 1;
	QString randomString;
	randomString.reserve(realLength);
	for (int i = 0; i < realLength; ++i)
	{
		int index = QRandomGenerator::global()->bounded(possibleCharactersLength);
		randomString.append(possibleCharacters.at(index));
	}
	return randomString;
}

QString QQSystemApi::getFileSizeString(qint64 size)
{
	if (size < 1024) {
		return QString::number(size) + "B";
	}
	else if (size < 1024 * 1024) {
		return QString::number(size / 1024) + "KB";
	}
	else if (size < 1024 * 1024 * 1024) {
		return QString::number(size / 1024 / 1024) + "MB";
	}
	else {
		return QString::number(size / 1024 / 1024 / 1024) + "GB";
	}
}
